/*
 *  PassBag is multi-platform software that securely manage/store passwords
 *  Copyright (C) <2009>  <Hugo Rodrigues PEREIRA>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *	
 *  You can find a copy of the GPLv3 at project <root directory>/gpl.txt
 *
 */

using System;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace PassBag.Presentation {
    /// <summary>
    /// Summary description for password.
    /// </summary>
    public class NewPasswordDialog : System.Windows.Forms.Form {
        private enum PasswordStrength {
            TooShort = 1,
            Mediocre = 2,
            Low = 3,
            Medium = 4,
            Ok = 5,
            Great = 6,
            Strength = 7
        };

        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.Label label2;
        protected System.Windows.Forms.Label label3;
        protected System.Windows.Forms.TextBox passField;
        protected System.Windows.Forms.TextBox confirmField;
        protected System.Windows.Forms.Label label4;
        protected System.Windows.Forms.Label entropyStatus;
        protected System.Windows.Forms.Button okBtn;
        protected System.Windows.Forms.Button cancelBtn;
        protected PictureBox passStrengthPictureBox;

        public string Password {
            get {
                return passField.Text;
            }
        }

        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;

        public NewPasswordDialog () {
            //
            // Required for Windows Form Designer support
            //
            InitializeComponent ();


            LoadRessource ();
        }

        #region Load Resource

        /// <summary>
        /// Loads the ressource.
        /// </summary>
        private void LoadRessource () {
            this.Text = Properties.Resources.NewPasswordDialog_Text;
            this.label1.Text = Properties.Resources.NewPasswordDialog_Title;
            this.label2.Text = Properties.Resources.NewPasswordDialog_SubTitle;
            this.label3.Text = Properties.Resources.NewPasswordDialog_PasswordTextTitle;
            this.label4.Text = Properties.Resources.NewPasswordDialog_ConfirmTextTitle;
            this.entropyStatus.Text = Properties.Resources.NewPasswordDialog_PasswordInfo;
            
            this.okBtn.Text = Properties.Resources.Global_OkButton;
            this.cancelBtn.Text = Properties.Resources.Global_CancelButton;
        }

        #endregion


        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose (bool disposing) {
            if (disposing) {
                if (components != null) {
                    components.Dispose ();
                }
            }
            base.Dispose (disposing);
        }

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent () {
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager (typeof (NewPasswordDialog));
            this.label1 = new System.Windows.Forms.Label ();
            this.label2 = new System.Windows.Forms.Label ();
            this.label3 = new System.Windows.Forms.Label ();
            this.passField = new System.Windows.Forms.TextBox ();
            this.confirmField = new System.Windows.Forms.TextBox ();
            this.label4 = new System.Windows.Forms.Label ();
            this.entropyStatus = new System.Windows.Forms.Label ();
            this.okBtn = new System.Windows.Forms.Button ();
            this.cancelBtn = new System.Windows.Forms.Button ();
            this.passStrengthPictureBox = new System.Windows.Forms.PictureBox ();
            ((System.ComponentModel.ISupportInitialize)(this.passStrengthPictureBox)).BeginInit ();
            this.SuspendLayout ();
            // 
            // label1
            // 
            this.label1.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.label1.Location = new System.Drawing.Point (8, 8);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size (136, 16);
            this.label1.TabIndex = 0;
            this.label1.Text = "Please enter a password.";
            // 
            // label2
            // 
            this.label2.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.label2.Location = new System.Drawing.Point (8, 32);
            this.label2.Name = "label2";
            this.label2.Size = new System.Drawing.Size (353, 34);
            this.label2.TabIndex = 1;
            this.label2.Text = "It is recommended that you enter a strong password by using a combination of A-Z," +
                " a-z, 0-9, and punctuation marks.";
            // 
            // label3
            // 
            this.label3.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.label3.Location = new System.Drawing.Point (8, 78);
            this.label3.Name = "label3";
            this.label3.Size = new System.Drawing.Size (60, 26);
            this.label3.TabIndex = 2;
            this.label3.Text = "Password:";
            this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
            // 
            // passField
            // 
            this.passField.Font = new System.Drawing.Font ("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.passField.Location = new System.Drawing.Point (74, 80);
            this.passField.MaxLength = 64;
            this.passField.Name = "passField";
            this.passField.PasswordChar = '*';
            this.passField.Size = new System.Drawing.Size (287, 22);
            this.passField.TabIndex = 0;
            this.passField.TextChanged += new System.EventHandler (this.passField_TextChanged);
            // 
            // confirmField
            // 
            this.confirmField.Font = new System.Drawing.Font ("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.confirmField.Location = new System.Drawing.Point (74, 107);
            this.confirmField.MaxLength = 64;
            this.confirmField.Name = "confirmField";
            this.confirmField.PasswordChar = '*';
            this.confirmField.Size = new System.Drawing.Size (287, 22);
            this.confirmField.TabIndex = 1;
            this.confirmField.KeyPress += new System.Windows.Forms.KeyPressEventHandler (this.confirmField_KeyPress);
            // 
            // label4
            // 
            this.label4.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.label4.Location = new System.Drawing.Point (8, 105);
            this.label4.Name = "label4";
            this.label4.Size = new System.Drawing.Size (60, 26);
            this.label4.TabIndex = 4;
            this.label4.Text = "Confirm:";
            this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
            // 
            // entropyStatus
            // 
            this.entropyStatus.Location = new System.Drawing.Point (8, 141);
            this.entropyStatus.Name = "entropyStatus";
            this.entropyStatus.Size = new System.Drawing.Size (312, 20);
            this.entropyStatus.TabIndex = 6;
            this.entropyStatus.Text = "Waiting for password entry...";
            // 
            // okBtn
            // 
            this.okBtn.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.okBtn.Location = new System.Drawing.Point (286, 190);
            this.okBtn.Name = "okBtn";
            this.okBtn.Size = new System.Drawing.Size (75, 23);
            this.okBtn.TabIndex = 2;
            this.okBtn.Text = "Ok";
            this.okBtn.Click += new System.EventHandler (this.okBtn_Click);
            // 
            // cancelBtn
            // 
            this.cancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel;
            this.cancelBtn.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.cancelBtn.Location = new System.Drawing.Point (205, 190);
            this.cancelBtn.Name = "cancelBtn";
            this.cancelBtn.Size = new System.Drawing.Size (75, 23);
            this.cancelBtn.TabIndex = 3;
            this.cancelBtn.Text = "Cancel";
            // 
            // passStrengthPictureBox
            // 
            this.passStrengthPictureBox.BackColor = System.Drawing.SystemColors.Control;
            this.passStrengthPictureBox.Location = new System.Drawing.Point (11, 161);
            this.passStrengthPictureBox.Name = "passStrengthPictureBox";
            this.passStrengthPictureBox.Size = new System.Drawing.Size (350, 7);
            this.passStrengthPictureBox.TabIndex = 9;
            this.passStrengthPictureBox.TabStop = false;
            // 
            // NewPasswordDialog
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size (5, 13);
            this.ClientSize = new System.Drawing.Size (370, 225);
            this.ControlBox = false;
            this.Controls.Add (this.passStrengthPictureBox);
            this.Controls.Add (this.cancelBtn);
            this.Controls.Add (this.okBtn);
            this.Controls.Add (this.entropyStatus);
            this.Controls.Add (this.confirmField);
            this.Controls.Add (this.label4);
            this.Controls.Add (this.passField);
            this.Controls.Add (this.label3);
            this.Controls.Add (this.label2);
            this.Controls.Add (this.label1);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
            this.Icon = ((System.Drawing.Icon)(resources.GetObject ("$this.Icon")));
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.Name = "NewPasswordDialog";
            this.ShowInTaskbar = false;
            this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
            this.Text = " New Password";
            this.Load += new System.EventHandler (this.passwordDlg_Load);
            ((System.ComponentModel.ISupportInitialize)(this.passStrengthPictureBox)).EndInit ();
            this.ResumeLayout (false);
            this.PerformLayout ();

        }
        #endregion

        private void passwordDlg_Load (object sender, System.EventArgs e) {

        }

        protected virtual void okBtn_Click (object sender, System.EventArgs e) {
            if (passField.TextLength < PassBag.Logic.Settings.XmlSettingsManager.Settings.MinPasswordLength) {
                MessageDialog.ShowError (this, Properties.Resources.NewPasswordDialog_MsgPassToShort);
            }
            else if (confirmField.TextLength == 0) {
                MessageDialog.ShowError (this, Properties.Resources.NewPasswordDialog_MsgConfirmEmpty);
            }
            else if (!passField.Text.Equals (confirmField.Text)) {
                // Fields don'toString match
                MessageDialog.ShowError (this, Properties.Resources.NewPasswordDialog_MsgDoNotMatch);
            }
            else {
                // If we get here, then its ok to dispose of the dialog and set DialogResult to OK
                DialogResult = DialogResult.OK;
                Close ();
            }
        }

        private void passField_TextChanged (object sender, System.EventArgs e) {
            checkEffectiveBitSize (passField.TextLength);
        }

        private void checkEffectiveBitSize (int passSize) {
            int charSet = 0;
            string passStrength = "";

            charSet = getCharSetUsed (passField.Text);

            double result = Math.Log (Math.Pow (charSet, passSize)) / Math.Log (2);

            //System.Diagnostics.Debug.Write ("result " + result + ", size " + passSize);

            if (result <= 25 || passSize < PassBag.Logic.Settings.XmlSettingsManager.Settings.MinPasswordLength ) {
                passStrength = Properties.Resources.NewPasswordDialog_TooShort;
                ShowPasswordStrengthImages (PasswordStrength.TooShort);
            }
            else if (result <= 30) {
                passStrength = Properties.Resources.NewPasswordDialog_MsgConfirmEmpty;
                ShowPasswordStrengthImages (PasswordStrength.Mediocre);
            }
            else if (result <= 40) {
                passStrength = Properties.Resources.NewPasswordDialog_Low;
                ShowPasswordStrengthImages (PasswordStrength.Low);
            }
            else if (result <= 50) {
                passStrength = Properties.Resources.NewPasswordDialog_Medium;
                ShowPasswordStrengthImages (PasswordStrength.Medium);
            }
            else if (result <= 60) {
                passStrength = Properties.Resources.NewPasswordDialog_Ok;
                ShowPasswordStrengthImages (PasswordStrength.Ok);
            }
            else if (result <= 75) {
                passStrength = Properties.Resources.NewPasswordDialog_Great;
                ShowPasswordStrengthImages (PasswordStrength.Great);
            }
            else if (result > 90) {
                passStrength = Properties.Resources.NewPasswordDialog_Strength;
                ShowPasswordStrengthImages (PasswordStrength.Strength);
            }

            entropyStatus.Text = string.Format (Properties.Resources.NewPasswordDialog_PassInfoChange, passStrength, Math.Round (result, 0));
        }

        private void ShowPasswordStrengthImages (PasswordStrength strength) {
            //
            switch (strength) {
                case PasswordStrength.TooShort:
                    passStrengthPictureBox.Image = Properties.Resources.Strength1;
                    break;
                case PasswordStrength.Mediocre:
                    passStrengthPictureBox.Image = Properties.Resources.Strength2;
                    break;
                case PasswordStrength.Low:
                    passStrengthPictureBox.Image = Properties.Resources.Strength3;
                    break;
                case PasswordStrength.Medium:
                    passStrengthPictureBox.Image = Properties.Resources.Strength4;
                    break;
                case PasswordStrength.Ok:
                    passStrengthPictureBox.Image = Properties.Resources.Strength5;
                    break;
                case PasswordStrength.Great:
                    passStrengthPictureBox.Image = Properties.Resources.Strength6;
                    break;
                case PasswordStrength.Strength:
                    passStrengthPictureBox.Image = Properties.Resources.Strength7;
                    break;
                default:
                    break;
            }
        }

        private int getCharSetUsed (string pass) {
            int ret = 0;

            if (containsNumbers (pass)) {
                ret += 10;
            }

            if (containsLowerCaseChars (pass)) {
                ret += 26;
            }

            if (containsUpperCaseChars (pass)) {
                ret += 26;
            }

            if (containsPunctuation (pass)) {
                ret += 31;
            }

            return ret;
        }

        private bool containsNumbers (string str) {
            Regex pattern = new Regex (@"[\d]");
            return pattern.IsMatch (str);
        }

        private bool containsLowerCaseChars (string str) {
            Regex pattern = new Regex ("[a-z]");
            return pattern.IsMatch (str);
        }

        private bool containsUpperCaseChars (string str) {
            Regex pattern = new Regex ("[A-Z]");
            return pattern.IsMatch (str);
        }

        private bool containsPunctuation (string str) {
            // regular expression include _ as a valid char for alphanumeric.. 
            // so we need to explicity state that its considered punctuation.
            Regex pattern = new Regex (@"[\W|_]");
            return pattern.IsMatch (str);
        }

        private void entropyStatus_Click (object sender, System.EventArgs e) {

        }

        private void confirmField_KeyPress (object sender, KeyPressEventArgs e) {
            if (e.KeyChar.Equals('\r')) {
                okBtn_Click (okBtn, null);                
            }
        }
    }

}
